#include "sampler.h"
#include "point.h"

Sample::Sample(Sampler *sampler, SurfaceIntegrator *surf, VolumeIntegrator *vol, const Scene *scene) {
	// TO DO, initialized with Integrator
	Warning("Sample struct construction not implemented yet\n");

	AllocateSampleMemory();
}

Sample::~Sample() {
	// Free memory
	if(oneD != NULL) {
		FreeAligned(oneD[0]);
		FreeAligned(oneD);
	}
	if(twoD != NULL) {
		FreeAligned(twoD[0]);
		FreeAligned(twoD);
	}
}

void Sample::AllocateSampleMemory() {
	// Allocate memory for oneD array
	int n = n1D.size();
	if(n == 0)
		oneD = NULL;
	else {
		oneD = AllocAligned<float*>(n);
		int totalSamples = 0;
		for(int i = 0; i < n; i++)
			totalSamples += n1D[i];
		float *mem = AllocAligned<float>(totalSamples);
		for(int i = 0; i < n; i++) {
			oneD[i] = mem;
			mem += n1D[i];
		}
	}
	// Allocate memory for twoD array
	n = n2D.size();
	if(n == 0)
		twoD = NULL;
	else {
		twoD = AllocAligned<Point2*>(n);
		int totalSamples = 0;
		for(int i = 0; i < n; i++)
			totalSamples += n2D[i];
		Point2 *mem = AllocAligned<Point2>(totalSamples);
		for(int i = 0; i < n; i++) {
			twoD[i] = mem;
			mem += n2D[i];
		}
	}
}

Sample *Sample::Duplicate(int count) const {
	Sample *ret = new Sample[count];
	for (int i = 0; i < count; ++i) {
		ret[i].n1D = n1D;
		ret[i].n2D = n2D;
		ret[i].AllocateSampleMemory();
	}
	return ret;
}

Sampler::Sampler(int xstart, int xend, int ystart, int yend, int spp, bool lns, bool ts) :
			xPixelStart(xstart), xPixelEnd(xend), 
			yPixelStart(ystart), yPixelEnd(yend), 
			samplePerPixel(spp), needLensSamples(lns), needTimeSamples(ts) {
}
Sampler::~Sampler() {
}

void Sampler::ComputeSubWindow(int num, int count, int *xstart, int *xend, int *ystart, int *yend) const {
	// num is the tile number
	// count is the total tile number
	
	// Determine how many tiles to use in each dimension, nx and ny
	int dx = xPixelEnd - xPixelStart, dy = yPixelEnd - yPixelStart;
	int nx = count, ny = 1;
	while((nx & 0x01) == 0 && 2 * dx * ny < dy * nx) {
		nx >>= 1;
		ny <<= 1;
	}

	// Compute x and y pixel range for sub-window
	int x0 = num % nx, y0 = num / nx;
	float tx0 = float(x0) / float(nx), tx1 = float(x0+1) / float(nx);
	float ty0 = float(y0) / float(ny), ty1 = float(y0+1) / float(ny);
	*xstart = Floor2Int(Lerp(tx0, xPixelStart, xPixelEnd));
	*xend = Floor2Int(Lerp(tx1, xPixelStart, xPixelEnd));
	*ystart = Floor2Int(Lerp(ty0, yPixelStart, yPixelEnd));
	*yend = Floor2Int(Lerp(ty1, yPixelStart, yPixelEnd));
}